/* editor.c */
/* author: jiqing (jiqingwu@gmail.com) */
/* create: 2011-12-26 */

#include <stdio.h>
#include "editor.h"
#include "assist.h"

#define VIDEO_WIDTH 970
#define VIDEO_HEIGHT 680

enum EDITKEY{
    key_show_grid     = (1 << 0),    // 'g'
    key_show_block    = (1 << 1),    // 'b'
    key_swap_layer    = (1 << 2),    // 'l'
    key_set_tile      = (1 << 3),    // space
    key_set_block     = (1 << 4),    // 'x'
    key_map_left      = (1 << 5),    // 'a'
    key_map_right     = (1 << 6),    // 'd'
    key_map_up        = (1 << 7),    // 'w'
    key_map_down      = (1 << 8),    // 's'
    key_res_left      = (1 << 9),    // left
    key_res_right     = (1 << 10),   // right
    key_res_up        = (1 << 11),   // up
    key_res_down      = (1 << 12),   // down
    key_quit          = (1 << 13),   // ESC
    key_save          = (1 << 14),   // 'f'
    key_clear_tile    = (1 << 15)    // 'c'
};

SDL_Event event;
static char map_file_name[256];


void editor_key_filter(MapEditor *editor, SDL_Event event)
{
    if(event.type == SDL_KEYUP){
        switch(event.key.keysym.sym){
        case SDLK_g:
            editor->key_pressed |= key_show_grid;
            break;
        case SDLK_b:
            editor->key_pressed |= key_show_block;
            break;
        case SDLK_SPACE:
            editor->key_pressed |= key_set_tile;
            break;
        case SDLK_c:
            editor->key_pressed |= key_clear_tile;
            break;
        case SDLK_x:
            editor->key_pressed |= key_set_block;
            break;
        case SDLK_a:
            editor->key_pressed |= key_map_left;
            break;
        case SDLK_d:
            editor->key_pressed |= key_map_right;
            break;
        case SDLK_w:
            editor->key_pressed |= key_map_up;
            break;
        case SDLK_s:
            editor->key_pressed |= key_map_down;
            break;
        case SDLK_LEFT:
            editor->key_pressed |= key_res_left;
            break;
        case SDLK_RIGHT:
            editor->key_pressed |= key_res_right;
            break;
        case SDLK_UP:
            editor->key_pressed |= key_res_up;
            break;
        case SDLK_DOWN:
            editor->key_pressed |= key_res_down;
            break;
        case SDLK_ESCAPE:
            editor->key_pressed |= key_quit;
            break;
        case SDLK_f:
            editor->key_pressed |= key_save;
        }
    }
}

void editor_init_video(MapEditor *editor, bool fullscreen)
{
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("Unable to initialize SDL: %s\n", SDL_GetError());
        exit(1);
    }

    atexit(SDL_Quit);

    if (fullscreen)
        editor->screen = SDL_SetVideoMode
            (VIDEO_WIDTH, VIDEO_HEIGHT, 16,
             SDL_DOUBLEBUF|SDL_FULLSCREEN);
    else
        editor->screen = SDL_SetVideoMode
            (VIDEO_WIDTH, VIDEO_HEIGHT, 16, SDL_DOUBLEBUF);

    if (editor->screen == NULL) {
        printf("Unable to set video mode: %s\n", SDL_GetError());
        exit(1);
    }

    SDL_WM_SetCaption("olMapEditor", NULL);

    SDL_ShowCursor(0); //hide mouse pointer
}

void editor_draw_select_box(MapEditor *editor,
                            int x, int y, int w, int h)
{
    boxColor(editor->screen, x, y, x + w, y + h, 0xffff0045);
    rectangleColor(editor->screen, x, y, x + w, y + h, 0xffff00ff);
}

void editor_draw_container(MapEditor *editor, SDL_Rect rect, 
                           bool highlight)
{
    if(highlight)
        boxColor(editor->screen, rect.x, rect.y, rect.x + rect.w,
                 rect.y + rect.h, 0xddddffff);
    else
        boxColor(editor->screen, rect.x, rect.y, rect.x + rect.w,
                 rect.y + rect.h, 0x000000ff);

    rectangleColor(editor->screen, rect.x, rect.y, rect.x + rect.w,
                   rect.y + rect.h, 0x00ff22ff);
}

void editor_draw_res_pic(MapEditor *editor)
{
    editor_draw_container(editor, editor->res_rect, false);

    SDL_Rect dest_rect;
    dest_rect.x = editor->res_rect.x + 1;
    dest_rect.y = editor->res_rect.y + 1;

    dest_rect.w = editor->surf_tile->w;
    dest_rect.h = editor->surf_tile->h;
    SDL_BlitSurface(editor->surf_tile, NULL, 
                    editor->screen, &dest_rect);
}

void editor_draw_msgbox(MapEditor *editor){

    // draw message frame
    editor_draw_container(editor, editor->msg_rect, false);

    // draw simple help information
    stringColor(editor->screen, editor->msg_rect.x + 10,
                editor->msg_rect.y + 10, 
                "g: show grid | b: show block | SPACE: set tile"
                " | x: set block", 0xffffffff);
    stringColor(editor->screen, editor->msg_rect.x + 10,
                editor->msg_rect.y + 25,
                "c: clear tile | "
                "f: save map | Esc: quit", 0xffffffff);

    // draw runtime message
    boxColor(editor->screen, editor->runtime_msg_rect.x,
             editor->runtime_msg_rect.y,
             editor->runtime_msg_rect.x + 
             editor->runtime_msg_rect.w,
             editor->runtime_msg_rect.y + 
             editor->runtime_msg_rect.h, 0x222222ff);
    stringColor(editor->screen, editor->runtime_msg_rect.x + 5,
                editor->runtime_msg_rect.y + 2, editor->runtime_msg,
                0xff0000ff);
}

void editor_update_screen(MapEditor *editor)
{
    // update map
    map_draw(editor->map, editor->screen, editor->surf_tile,
             editor->show_grid, editor->show_block);
    editor_draw_select_box(editor, editor->map_select_x * TILE_SIZE,
                           editor->map_select_y * TILE_SIZE,
                           TILE_SIZE, TILE_SIZE);

    // update message box
    sprintf(editor->runtime_msg,
            "[ %s ]  w: %d, h: %d | x: %d, y: %d | %s",
            map_file_name, editor->map->size_x, editor->map->size_y,
            editor->map_select_x, editor->map_select_y,
            editor->show_block? "show block" : "hide block");
    editor_draw_msgbox(editor);

    // update spirite surface
    editor_draw_res_pic(editor);
    editor_draw_select_box(editor, editor->res_rect.x + 1 + 
                           editor->res_select_x * TILE_SIZE,
                           editor->res_rect.y + 1 + 
                           editor->res_select_y * TILE_SIZE,
                           TILE_SIZE, TILE_SIZE);
    SDL_Flip(editor->screen);
}

void editor_handle_keys(MapEditor *editor)
{
    if(editor->key_pressed & key_quit){
        editor->running = 0;
    }
    else if(editor->key_pressed & key_save){
        map_save(editor->map, map_file_name);
        sprintf(editor->runtime_msg, "%s has been saved!",
                map_file_name);
        printf("%s\n", editor->runtime_msg);
        editor_draw_msgbox(editor);
    }
    else if(editor->key_pressed & key_show_grid){
        editor->show_grid = !editor->show_grid;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_show_block){
        editor->show_block = !editor->show_block;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_set_tile){
        int k = editor->map_select_y * editor->map->size_x +
            editor->map_select_x;
        int tile_index = editor->res_select_y * editor->surf_size_x
            + editor->res_select_x;
        editor->map->tiles[k].tile_index = tile_index;

        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_clear_tile){
        int k = editor->map_select_y * editor->map->size_x +
            editor->map_select_x;
        editor->map->tiles[k].tile_index = -1;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_set_block){
        int k = editor->map_select_y * editor->map->size_x +
            editor->map_select_x;
        editor->map->tiles[k].block = !editor->map->tiles[k].block;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_map_left){
        if(editor->map_select_x == 0){
            if(editor->map_select_y > 0){
                editor->map_select_y --;
                editor->map_select_x = editor->map->size_x -1;
            }
        }
        else
            editor->map_select_x --;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_map_right){
        editor->map_select_x ++;
        if(editor->map_select_x == editor->map->size_x){
            if(editor->map_select_y < editor->map->size_y -1){
                editor->map_select_y ++;
                editor->map_select_x = 0;
            }
            else
                editor->map_select_x --;
        }
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_map_up){
        if(editor->map_select_y == 0)
            editor->map_select_y = (*editor).map->size_y - 1;
        else
            editor->map_select_y --;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_map_down){
        editor->map_select_y ++;
        if(editor->map_select_y == editor->map->size_y)
            editor->map_select_y = 0;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_res_left){
        if(editor->res_select_x == 0){
            if(editor->res_select_y > 0){
                editor->res_select_y --;
                editor->res_select_x = editor->surf_size_x - 1;
            }
        }
        else
            editor->res_select_x --;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_res_right){
        if(editor->res_select_x == editor->surf_size_x - 1){
            if(editor->res_select_y < editor->surf_size_y - 1){
                editor->res_select_y ++;
                editor->res_select_x = 0;
            }
        }
        else
            editor->res_select_x ++;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_res_up){
        if(editor->res_select_y == 0)
            editor->res_select_y = editor->surf_size_y - 1;
        else
            editor->res_select_y -- ;
        editor_update_screen(editor);
    }
    else if(editor->key_pressed & key_res_down){
        if(editor->res_select_y == editor->surf_size_y - 1)
            editor->res_select_y = 0;
        else
            editor->res_select_y ++ ;
        editor_update_screen(editor);
    }

    editor->key_pressed = 0;
}

bool editor_create_tile_surf(MapEditor *editor,
                              const char *tile_bmp_name)
{
    CreateBmpSurface(&editor->surf_tile, tile_bmp_name);
    return true;
}

int editor_init(MapEditor *editor, 
                const char *map_file_name,
                const char *tile_bmp_name)
{
    // if the map file doesn't exist or can't r/w,
    // then create a new map
    // else load map from file
    if(access(map_file_name, 0x06) < 0)
        editor->map = map_new(DEFAULT_MAP_WIDTH, 
                              DEFAULT_MAP_HEIGHT);
    else
        editor->map = map_load(map_file_name);
    if(!editor->map){
        printf("map file %s load failed!\n", map_file_name);
        return -1;
    }

    // create tile surface
    editor_create_tile_surf(editor, tile_bmp_name);
    editor->surf_size_x = editor->surf_tile->w / TILE_SIZE;
    editor->surf_size_y = editor->surf_tile->h / TILE_SIZE;

    editor->show_grid = false;
    editor->show_block = false;

    // tile surface box
    editor->res_rect.x = 645 - 1;
    editor->res_rect.y = 2 - 1;
    editor->res_rect.w = 320 + 2;
    editor->res_rect.h = 668 + 2;

    // message and information box
    editor->msg_rect.x = 5;
    editor->msg_rect.y = 610;
    editor->msg_rect.w = 635;
    editor->msg_rect.h = 60;
    editor->runtime_msg_rect.x = 6;
    editor->runtime_msg_rect.y = 655;
    editor->runtime_msg_rect.w = 633;
    editor->runtime_msg_rect.h = 14;
    strcpy(editor->runtime_msg, "");

    editor->map_select_x = 0;
    editor->map_select_y = 0;
    editor->res_select_x = 0;
    editor->res_select_y = 0;

    editor->key_pressed = 0;
    editor->running = true;
}

void editor_shutdown(MapEditor *editor)
{
    map_destroy(editor->map);

    SDL_FreeSurface(editor->surf_tile);
    editor->surf_tile = NULL;
}

int main(int argc, char* argv[])
{
    if(argc < 2){
        printf("usage: mapeditor <mapfilename>\n");
        return -1;
    }

    if( strcmp(argv[1], "-h") == 0){
        printf("This is a RPG map editor.\n");
        printf("Author: Jiqing Wu(jiqingwu@gmail.com)\n");
        printf("usage: mapeditor <mapfilename>\n");
        printf("mapeditor -h show this help message.\n");
        printf("The new version will support more options.\n");
        printf("Have Fun!!!\n");
        return 0;
    }

    strcpy(map_file_name, argv[1]);

    MapEditor editor;
    editor_init_video(&editor, false);
    editor_init(&editor, map_file_name, "floor.bmp");

    editor_update_screen(&editor);

    while(editor.running) {
        if(SDL_WaitEvent(&event)){
            if(event.type == SDL_QUIT)
                break;
            editor_key_filter(&editor, event);
            editor_handle_keys(&editor);
        }
    }

    editor_shutdown(&editor);
}
